package ndfs.tree;

public class Tree {

	private TreeNode root;
	
	public Tree(){
		root = new TreeNode(0); //Hash ints start at 1, so initialize at 0;
	}
	
	public void add(TreeNode toAdd){
		TreeNode currentNode = root;
		currentNode.lock();
		TreeNode nextNode;
		while(true){
			if(toAdd.getHash() > currentNode.getHash()){
				// Node should be added to the right
				nextNode = currentNode.getRightChild();
				if(nextNode == null){
					currentNode.setRightChild(toAdd);
					currentNode.unlock();
					return;
				}
			} else if(toAdd.getHash() < currentNode.getHash()){
				// Node should be added left;
				nextNode = currentNode.getLeftChild();
				if(nextNode == null){
					currentNode.setLeftChild(toAdd);
					currentNode.unlock();
					return;
				}
			} else{
				// Node already exists in tree, therefore does not have to be added
				// in our context we can just return;
				return;
			}
			nextNode.lock();
			currentNode.unlock();
			currentNode = nextNode;
		}
	}
	
	public boolean isRed(int hash){
		TreeNode currentNode = root;
		while(true){
			if(hash > currentNode.getHash()){
				currentNode = currentNode.getRightChild();
			} else if (hash < currentNode.getHash()){
				currentNode = currentNode.getLeftChild();
			} else{
				// Hash is the same.
				return currentNode.getRed();
			}
		}
	}
	
	public void setRed(int hash){
		TreeNode currentNode = root;
		while(true){
			if(hash > currentNode.getHash()){
				currentNode = currentNode.getRightChild();
			} else if (hash < currentNode.getHash()){
				currentNode = currentNode.getLeftChild();
			} else{
				// Hash is the same.
				currentNode.setRed(true);
				return;
			}
		}
	}
	
	public void incrementCounter(int hash){
		TreeNode currentNode = root;
		while(true){
			if(hash > currentNode.getHash()){
				currentNode = currentNode.getRightChild();
			} else if (hash < currentNode.getHash()){
				currentNode = currentNode.getLeftChild();
			} else{
				// Hash is the same.
				currentNode.incrementCounter();
				return;
			}
		}
	}
	
	public void decrementCounter(int hash){
		TreeNode currentNode = root;
		while(true){
			if(hash > currentNode.getHash()){
				currentNode = currentNode.getRightChild();
			} else if (hash < currentNode.getHash()){
				currentNode = currentNode.getLeftChild();
			} else{
				// Hash is the same.
				currentNode.decrementCounter();
				return;
			}
		}
	}
	
	public int getCounter(int hash){
		TreeNode currentNode = root;
		while(true){
			if(hash > currentNode.getHash()){
				currentNode = currentNode.getRightChild();
			} else if (hash < currentNode.getHash()){
				currentNode = currentNode.getLeftChild();
			} else{
				// Hash is the same.
				return currentNode.getCounter();
			}
		}
	}
	
}
